package com.dm.cloud.service.impl;

import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.dm.cloud.api.dto.Resources;
import com.dm.cloud.api.dto.UserDepartment;
import com.dm.cloud.api.dto.UserRole;
import com.dm.cloud.api.dto.Users;
import com.dm.cloud.api.service.IUserAccountService;
import com.dm.cloud.api.vo.*;
import com.dm.cloud.common.CloudConstant;
import com.dm.cloud.common.R;
import com.dm.cloud.dao.UserDepartmentDao;
import com.dm.cloud.dao.UserRoleDao;
import com.dm.cloud.dao.UsersDao;
import com.dm.cloud.databases.redis.JedisUtils;
import com.dm.cloud.utils.MysqlLogger;
import com.dm.cloud.configurations.Oauth2Utils;
import com.dm.cloud.utils.SpringContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UserAccountServiceImpl implements IUserAccountService {

    @Autowired
    private UsersDao usersDao;

    @Autowired
    private UserRoleDao userRoleDao;

    @Autowired
    private UserDepartmentDao userDepartmentDao;


    @Override
    @Transactional
    public R createAccount(UsersVo usersVo, int type) {

        Users users = new Users();
        BeanUtils.copyProperties(usersVo,users);

        //自己创建的
        if(StringUtils.isBlank(usersVo.getPassword())){
            return R.failure("请设置密码！");
        }

        if(type == 0){
            //判断验证码是否正确
            String smsCode = JedisUtils.getString("reg"+ usersVo.getPhoneNo());
            if(StringUtils.isBlank(smsCode)){
                return R.failure("验证码未生成或已失效！");
            }
            if(!usersVo.getSmsCode().equals(smsCode)){
                return R.failure("验证码错误！");
            }
        }
        if(StringUtils.isBlank(users.getUserName())){
            return R.failure("账户不能为空！");
        }
        if(StringUtils.isBlank(users.getPassword())){
            return R.failure("密码不能为空！");
        }

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(10);
        String passwrodEncode = encoder.encode(users.getPassword());
        users.setPassword(passwrodEncode);

        try{
            //查询账户是否存在
            QueryWrapper<Users> queryWrapper =new QueryWrapper<>();
            queryWrapper.eq("user_name", users.getUserName());
            queryWrapper.eq("delete_flag", 0);
            long accounts = usersDao.selectCount(queryWrapper);
            if(accounts>0){
                return R.failure("该账户已存在！");
            }

            //查询手机号是否存在
            if(Strings.isNotBlank(users.getPhoneNo())) {
                queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("phone_no", users.getPhoneNo());
                queryWrapper.eq("delete_flag", 0);
                long phones = usersDao.selectCount(queryWrapper);
                if (phones > 0) {
                    return R.failure("该手机已注册！");
                }
            }

            //记录注册时间
            users.setRegisterTime(new Date());
            usersDao.insert(users);
            //获取ID
            queryWrapper.last(" limit 1 ");
            users = usersDao.selectOne(queryWrapper);
            MysqlLogger.info(String.format("创建账户【%s】", usersVo.getUserName()));
        }catch (Exception ex){
            log.error(String.format("创建账户【%s】失败", usersVo.getUserName()),ex.getCause());
            return R.failure("系统异常,注册失败！");
        }

        if(type == 1) {
            try{
                //更新所属部门
                if (null != usersVo.getDepartmentId()) {
                    //先删除之前的角色信息
                    QueryWrapper deleteQ = new QueryWrapper();
                    deleteQ.eq("user_id", users.getId());
                    userDepartmentDao.delete(deleteQ);
                    //再保留新的角色信息
                    UserDepartment ud = new UserDepartment();
                    ud.setUserId(users.getId());
                    ud.setDepartmentId(usersVo.getDepartmentId());
                    userDepartmentDao.insert(ud);
                }
            }catch (Exception ex){
                log.error(String.format("创建账户【%s】失败", usersVo.getUserName()),ex.getCause());
                return R.failure("账户已创建,部门分配失败！");
            }
            try{
                //更新所属角色
                if (CollectionUtils.isNotEmpty(usersVo.getRoleId())) {
                    List<Integer> roles = usersVo.getRoleId().stream().filter(e -> null != e).collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(roles)) {

                        //先删除之前的角色信息
                        QueryWrapper deleteQ = new QueryWrapper();
                        deleteQ.eq("user_id", users.getId());
                        userRoleDao.delete(deleteQ);
                        //再保留新的角色信息

                        List<UserRole> insertList = new ArrayList<>();

                        for (Integer role : roles) {
                            UserRole ud = new UserRole();
                            ud.setUserId(users.getId());
                            ud.setRoleId(role);
                            insertList.add(ud);
                        }
                        userRoleDao.batchInsert(insertList);
                    }
                }
            }catch (Exception ex){
                log.error(String.format("创建账户【%s】失败", usersVo.getUserName()),ex.getCause());
                return R.failure("账户已创建,角色分配失败！");
            }
        }else if (type ==0){
            //用户自主注册 删除注册时候用的验证码
            JedisUtils.delValue("reg"+users.getPhoneNo());
        }

        return R.success();
    }

    @Override
    @Transactional
    public R updateAccount(UsersVo usersVo) {

        Users users = new Users();
        BeanUtils.copyProperties(usersVo,users);

        users.setUserName(null);//不能修改账户名

        if(usersDao.updateById(users)>0){
            //更新所属部门
            if(null != usersVo.getDepartmentId()){
                //先删除之前的角色信息
                QueryWrapper deleteQ = new QueryWrapper();
                deleteQ.eq("user_id",usersVo.getId());
                userDepartmentDao.delete(deleteQ);
                //再保留新的角色信息
                UserDepartment ud =new UserDepartment();
                ud.setUserId(usersVo.getId());
                ud.setDepartmentId(usersVo.getDepartmentId());
                userDepartmentDao.insert(ud);
            }

            //更新所属角色
            if(CollectionUtils.isNotEmpty(usersVo.getRoleId()) ){
                List<Integer> roles = usersVo.getRoleId().stream().filter(e->null != e).collect(Collectors.toList());
                if(CollectionUtils.isNotEmpty(roles) ){

                    //先删除之前的角色信息
                    QueryWrapper deleteQ = new QueryWrapper();
                    deleteQ.eq("user_id",usersVo.getId());
                    userRoleDao.delete(deleteQ);
                    //再保留新的角色信息

                    List<UserRole> insertList = new ArrayList<>();

                    for (Integer role : roles) {
                        UserRole ud =new UserRole();
                        ud.setUserId(usersVo.getId());
                        ud.setRoleId(role);
                        insertList.add(ud);
                    }

                    userRoleDao.batchInsert(insertList);
                }
            }

            MysqlLogger.info(String.format("修改账户【%s】信息",usersVo.getUserName()));
            return R.success("修改成功！");
        }else{
            log.error(String.format("修改账户【%s】信息失败",usersVo.getUserName()));
            return R.failure("修改失败！");
        }
    }

    @Override
    public R deleteAccount(UsersVo usersVo) {
        UpdateWrapper<Users> updateWapper =new UpdateWrapper<>();
        updateWapper.setSql("delete_flag=1,delete_time = now()")
                .eq("id",usersVo.getId());

        if(usersDao.update(null,updateWapper)>0){
            MysqlLogger.info(String.format("删除账户【%s】",usersVo.getUserName()));
            return R.success("账号删除成功！");
        }else{
            log.error(String.format("删除账户【%s】失败",usersVo.getUserName()));
            return R.failure("账号删除失败！");
        }
    }

    @Override
    public R smsCreate(String phoneNo, String type) {

        //查询手机号的详细信息
        QueryWrapper<Users> usersQueryWrapper =new QueryWrapper<>();
        usersQueryWrapper.eq("phone_no",phoneNo).eq("delete_flag",0);

        Users user = usersDao.selectOne(usersQueryWrapper);

        if(null == user && "login".equals(type)){
            return R.failure("该手机号未注册或未绑定账号！");
        }
        if(null != user && "register".equals(type)){
            return R.failure("改手机号已注册！");
        }

        //获取一个六位随机数
        int sms = (int)((Math.random()*9+1)*100000);
        try {
            //默认是登陆用的smsCode
            String phoneKey = phoneNo ;
            //注册用的区分开来
            if("register".equals(type)){
                phoneKey = "reg" + phoneKey ;
            }else if("login".equals(type)){
                phoneKey = "sms" + phoneKey ;
            }
            Object phoneValue = JedisUtils.getString(phoneKey);

            if(phoneValue!=null && Strings.isNotBlank(String.valueOf(phoneValue))){
                return R.failure("验证码已下发，请稍后重试！");
            }else{
                int redissEx =Integer.valueOf(SpringContextUtils.getProperty("custom.datasource.redis.smsExpire").toString());
                boolean success = false;

                if("register".equals(type)){
                    success = JedisUtils.setValue(phoneKey,sms);
                }else if("login".equals(type)){
                    success = JedisUtils.setValue(phoneKey,sms , redissEx);
                }

                if(success){
                    return R.success(sms);
                }else{
                    log.error(String.format("手机号【%s】验证码生成失败",phoneNo));
                    return R.failure("验证码下发失败，请重试！");
                }
            }
        }catch (Exception ex){
            log.error(String.format("手机号【%s】验证码生成失败",phoneNo));
            return R.failure("验证码下发失败，请重试！");
        }
    }

    @Override
    public R logoutAccount() {

        String authorization = Oauth2Utils.getAuthorization();
        UserDetails user = Oauth2Utils.getByAuthorization(authorization);

        try{
            Oauth2Utils.revokeToken(authorization);
            MysqlLogger.info(String.format("账号【%s】登出",user.getUsername()));
            return R.success("登出成功");
        }catch(Exception ex){
            log.error(String.format("账号【%s】登出失败",user.getUsername()));
            return R.failure("登出失败！");
        }
    }

    @Override
    public R selectPage(UsersVo usersVo) {

        List<UsersVo> result = new ArrayList<>();

        List<Users> list = usersDao.selectListJoinDepartment(usersVo);

        for (Users users1 : list) {
            UsersVo rin = new UsersVo();
            BeanUtils.copyProperties(users1,rin);
            result.add(rin);
        }
        return R.success(result);
    }

    @Override
    public R searchAccount(String id) {
        UsersVo result = new UsersVo();

        QueryWrapper<Users> usersQueryWrapper = new QueryWrapper<>();
        usersQueryWrapper.eq("delete_flag",0);
        usersQueryWrapper.eq("id",id);
        Users record = usersDao.selectOne(usersQueryWrapper);

        if(null != record){
            BeanUtils.copyProperties(record,result);
            //查询部门信息
            QueryWrapper searcher = new QueryWrapper();
            searcher.eq("user_id",id);
            searcher.last(" limit 1 ");
            UserDepartment ud = userDepartmentDao.selectOne(searcher);
            if(ObjectUtils.isNotNull(ud)){
                result.setDepartmentId(ud.getDepartmentId());
            }
            //查询角色信息
            searcher = new QueryWrapper();
            searcher.eq("user_id",id);
            List<UserRole> ur = userRoleDao.selectList(searcher);
            if(CollectionUtils.isNotEmpty(ur)){
                result.setRoleId(ur.stream().map(e->e.getRoleId()).collect(Collectors.toList()));
            }
        }

        return R.success(result);
    }

    @Override
    public R getMenuList() {

        MenuListVo resultContainer = new MenuListVo();
        resultContainer.setType("layout");

        //账户名是唯一的
        String authorization = Oauth2Utils.getAuthorization();
        UserDetails user = Oauth2Utils.getByAuthorization(authorization);
        QueryWrapper<Users> usersQueryWrapper = new QueryWrapper<>();
        usersQueryWrapper.eq("user_name",user.getUsername());
        usersQueryWrapper.eq("delete_flag",0);
        Users userforone = usersDao.selectOne(usersQueryWrapper);

        List<Resources> list = usersDao.selectResources(userforone.getId());

        if(CollectionUtils.isNotEmpty(list)){
            //整理菜单 去除按钮
            list = list.stream().filter(e->2 != e.getType()).collect(Collectors.toList());
            setChildTree(resultContainer,list);
        }

        return R.success(resultContainer.getChildren());
    }

    @Override
    public R getPermissions() {
        String authorization = Oauth2Utils.getAuthorization();
        UserDetails user = Oauth2Utils.getByAuthorization(authorization);
        QueryWrapper<Users> usersQueryWrapper = new QueryWrapper<>();
        usersQueryWrapper.eq("user_name",user.getUsername());
        usersQueryWrapper.eq("delete_flag",0);
        Users userforone = usersDao.selectOne(usersQueryWrapper);
        List<String> permissions = usersDao.selectPermissions(userforone.getId());

        return R.success(permissions);
    }

    @Override
    public R getUserInfo() {
        String authorization = Oauth2Utils.getAuthorization();
        UserDetails user = Oauth2Utils.getByAuthorization(authorization);
        QueryWrapper<Users> usersQueryWrapper = new QueryWrapper<>();
        usersQueryWrapper.eq("user_name",user.getUsername());
        usersQueryWrapper.eq("delete_flag",0);
        Users userforone = usersDao.selectOne(usersQueryWrapper);
        Users record = usersDao.selectById(userforone.getId());
        UserInfoVo result = new UserInfoVo();
        result.setUserId(record.getId());
        result.setRealName(record.getRealName());
        result.setUsername(record.getUserName());
        //默认打开的地址
        result.setHomePath("/dashboard/analysis");
        return R.success(result);
    }

    @Override
    public R<Users> getCurrentUser(String uuid) {
        //内部请求会带UUID
        if(CloudConstant.AUTH_REQUEST_UUID.equals(uuid)) {
            String authorization = Oauth2Utils.getAuthorization();
            UserDetails user = Oauth2Utils.getByAuthorization(authorization);
            QueryWrapper<Users> usersQueryWrapper = new QueryWrapper<>();
            usersQueryWrapper.eq("user_name", user.getUsername());
            usersQueryWrapper.eq("delete_flag", 0);
            Users userforone = usersDao.selectOne(usersQueryWrapper);
            return R.data(userforone);
        }else{
            return R.failure("未获取到用户信息");
        }
    }

    @Override
    public R<List<Users>> getUserList() {
        List<Users> users = new ArrayList<>();
        QueryWrapper<Users> wrapper = new QueryWrapper<>();
        wrapper.eq("delete_flag",0);
        users = usersDao.selectList(wrapper);

        return R.data(users);
    }

    /**
     * 整理菜单树信息
     * @param result
     * @param resources
     */
    private void setChildTree(MenuListVo result, List<Resources> resources){

        if(result == null || CollectionUtils.isEmpty(result.getChildren())){
            //先初始化 在循环
            String currentId = "" ;

            //判断是不是根节点
            if(!"layout".equals(result.getType())){
                currentId = result.getId().toString();
            }

            String finalCurrentId = currentId;
            result.setChildren(resources.stream()
                    .map(e->{
                        if(StringUtils.isBlank(e.getParentId())){
                            e.setParentId("");
                        }
                        return e;
                    }).filter(e-> finalCurrentId.equals(e.getParentId()))
                    .map(e->{
                        MenuListVo menu = new MenuListVo();
                        menu.setId(e.getId());
                        menu.setPath(e.getPath());
                        menu.setComponent(e.getUrl());
                        //这个是用来标志页面的唯一的 重复标题会导致前端页面打不开 给个随机数
                        menu.setName(UUID.randomUUID().toString());
                        menu.setSortNumber(e.getSortNumber());
                        MenuMeta meta = new MenuMeta(e.getTitle(),e.getIcon());
                        if(1 == e.getIsOut()) {
                            meta.setFrameSrc(e.getComponentUrl());
                        }
                        menu.setMeta(meta);

                        return menu;
                    }).sorted(new Comparator<MenuListVo>() {
                        @Override
                        public int compare(MenuListVo o1, MenuListVo o2) {
                            return o1.getSortNumber().compareTo(o2.getSortNumber());
                        }
                    }).collect(Collectors.toList()));

            if(CollectionUtils.isEmpty(result.getChildren())){
                return;
            }
            setChildTree(result,resources);
        }else{
            for (MenuListVo menu : result.getChildren()) {
                setChildTree(menu,resources);
            }
        }
    }
}
